home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / rational.rb < prev    next >
Encoding:
Ruby Source  |  2006-02-19  |  11.6 KB  |  531 lines

  1. #
  2. #   rational.rb -
  3. #       $Release Version: 0.5 $
  4. #       $Revision: 1.7 $
  5. #       $Date: 1999/08/24 12:49:28 $
  6. #       by Keiju ISHITSUKA(SHL Japan Inc.)
  7. #
  8. # Documentation by Kevin Jackson and Gavin Sinclair.
  9. # When you <tt>require 'rational'</tt>, all interactions between numbers
  10. # potentially return a rational result.  For example:
  11. #
  12. #   1.quo(2)              # -> 0.5
  13. #   require 'rational'
  14. #   1.quo(2)              # -> Rational(1,2)
  15. # See Rational for full documentation.
  16. #
  17.  
  18.  
  19. #
  20. # Creates a Rational number (i.e. a fraction).  +a+ and +b+ should be Integers:
  21. #   Rational(1,3)           # -> 1/3
  22. #
  23. # Note: trying to construct a Rational with floating point or real values
  24. # produces errors:
  25. #
  26. #   Rational(1.1, 2.3)      # -> NoMethodError
  27. #
  28. def Rational(a, b = 1)
  29.   if a.kind_of?(Rational) && b == 1
  30.     a
  31.   else
  32.     Rational.reduce(a, b)
  33.   end
  34. end
  35.  
  36. #
  37. # Rational implements a rational class for numbers.
  38. #
  39. # <em>A rational number is a number that can be expressed as a fraction p/q
  40. # where p and q are integers and q != 0.  A rational number p/q is said to have
  41. # numerator p and denominator q.  Numbers that are not rational are called
  42. # irrational numbers.</em> (http://mathworld.wolfram.com/RationalNumber.html)
  43. #
  44. # To create a Rational Number:
  45. #   Rational(a,b)             # -> a/b
  46. #   Rational.new!(a,b)        # -> a/b
  47. #
  48. # Examples:
  49. #   Rational(5,6)             # -> 5/6
  50. #   Rational(5)               # -> 5/1
  51. # Rational numbers are reduced to their lowest terms:
  52. #   Rational(6,10)            # -> 3/5
  53. #
  54. # But not if you use the unusual method "new!":
  55. #   Rational.new!(6,10)       # -> 6/10
  56. #
  57. # Division by zero is obviously not allowed:
  58. #   Rational(3,0)             # -> ZeroDivisionError
  59. #
  60. class Rational < Numeric
  61.   @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
  62.  
  63.   #
  64.   # Reduces the given numerator and denominator to their lowest terms.  Use
  65.   # Rational() instead.
  66.   #
  67.   def Rational.reduce(num, den = 1)
  68.     raise ZeroDivisionError, "denominator is zero" if den == 0
  69.  
  70.     if den < 0
  71.       num = -num
  72.       den = -den
  73.     end
  74.     gcd = num.gcd(den)
  75.     num = num.div(gcd)
  76.     den = den.div(gcd)
  77.     if den == 1 && defined?(Unify)
  78.       num
  79.     else
  80.       new!(num, den)
  81.     end
  82.   end
  83.  
  84.   #
  85.   # Implements the constructor.  This method does not reduce to lowest terms or
  86.   # check for division by zero.  Therefore #Rational() should be preferred in
  87.   # normal use.
  88.   #
  89.   def Rational.new!(num, den = 1)
  90.     new(num, den)
  91.   end
  92.  
  93.   private_class_method :new
  94.  
  95.   #
  96.   # This method is actually private.
  97.   #
  98.   def initialize(num, den)
  99.     if den < 0
  100.       num = -num
  101.       den = -den
  102.     end
  103.     if num.kind_of?(Integer) and den.kind_of?(Integer)
  104.       @numerator = num
  105.       @denominator = den
  106.     else
  107.       @numerator = num.to_i
  108.       @denominator = den.to_i
  109.     end
  110.   end
  111.  
  112.   #
  113.   # Returns the addition of this value and +a+.
  114.   #
  115.   # Examples:
  116.   #   r = Rational(3,4)      # -> Rational(3,4)
  117.   #   r + 1                  # -> Rational(7,4)
  118.   #   r + 0.5                # -> 1.25
  119.   #
  120.   def + (a)
  121.     if a.kind_of?(Rational)
  122.       num = @numerator * a.denominator
  123.       num_a = a.numerator * @denominator
  124.       Rational(num + num_a, @denominator * a.denominator)
  125.     elsif a.kind_of?(Integer)
  126.       self + Rational.new!(a, 1)
  127.     elsif a.kind_of?(Float)
  128.       Float(self) + a
  129.     else
  130.       x, y = a.coerce(self)
  131.       x + y
  132.     end
  133.   end
  134.  
  135.   #
  136.   # Returns the difference of this value and +a+.
  137.   # subtracted.
  138.   #
  139.   # Examples:
  140.   #   r = Rational(3,4)    # -> Rational(3,4)
  141.   #   r - 1                # -> Rational(-1,4)
  142.   #   r - 0.5              # -> 0.25
  143.   #
  144.   def - (a)
  145.     if a.kind_of?(Rational)
  146.       num = @numerator * a.denominator
  147.       num_a = a.numerator * @denominator
  148.       Rational(num - num_a, @denominator*a.denominator)
  149.     elsif a.kind_of?(Integer)
  150.       self - Rational.new!(a, 1)
  151.     elsif a.kind_of?(Float)
  152.       Float(self) - a
  153.     else
  154.       x, y = a.coerce(self)
  155.       x - y
  156.     end
  157.   end
  158.  
  159.   #
  160.   # Returns the product of this value and +a+.
  161.   #
  162.   # Examples:
  163.   #   r = Rational(3,4)    # -> Rational(3,4)
  164.   #   r * 2                # -> Rational(3,2)
  165.   #   r * 4                # -> Rational(3,1)
  166.   #   r * 0.5              # -> 0.375
  167.   #   r * Rational(1,2)    # -> Rational(3,8)
  168.   #
  169.   def * (a)
  170.     if a.kind_of?(Rational)
  171.       num = @numerator * a.numerator
  172.       den = @denominator * a.denominator
  173.       Rational(num, den)
  174.     elsif a.kind_of?(Integer)
  175.       self * Rational.new!(a, 1)
  176.     elsif a.kind_of?(Float)
  177.       Float(self) * a
  178.     else
  179.       x, y = a.coerce(self)
  180.       x * y
  181.     end
  182.   end
  183.  
  184.   #
  185.   # Returns the quotient of this value and +a+.
  186.   #   r = Rational(3,4)    # -> Rational(3,4)
  187.   #   r / 2                # -> Rational(3,8)
  188.   #   r / 2.0              # -> 0.375
  189.   #   r / Rational(1,2)    # -> Rational(3,2)
  190.   #
  191.   def / (a)
  192.     if a.kind_of?(Rational)
  193.       num = @numerator * a.denominator
  194.       den = @denominator * a.numerator
  195.       Rational(num, den)
  196.     elsif a.kind_of?(Integer)
  197.       raise ZeroDivisionError, "division by zero" if a == 0
  198.       self / Rational.new!(a, 1)
  199.     elsif a.kind_of?(Float)
  200.       Float(self) / a
  201.     else
  202.       x, y = a.coerce(self)
  203.       x / y
  204.     end
  205.   end
  206.  
  207.   #
  208.   # Returns this value raised to the given power.
  209.   #
  210.   # Examples:
  211.   #   r = Rational(3,4)    # -> Rational(3,4)
  212.   #   r ** 2               # -> Rational(9,16)
  213.   #   r ** 2.0             # -> 0.5625
  214.   #   r ** Rational(1,2)   # -> 0.866025403784439
  215.   #
  216.   def ** (other)
  217.     if other.kind_of?(Rational)
  218.       Float(self) ** other
  219.     elsif other.kind_of?(Integer)
  220.       if other > 0
  221.     num = @numerator ** other
  222.     den = @denominator ** other
  223.       elsif other < 0
  224.     num = @denominator ** -other
  225.     den = @numerator ** -other
  226.       elsif other == 0
  227.     num = 1
  228.     den = 1
  229.       end
  230.       Rational.new!(num, den)
  231.     elsif other.kind_of?(Float)
  232.       Float(self) ** other
  233.     else
  234.       x, y = other.coerce(self)
  235.       x ** y
  236.     end
  237.   end
  238.  
  239.   #
  240.   # Returns the remainder when this value is divided by +other+.
  241.   #
  242.   # Examples:
  243.   #   r = Rational(7,4)    # -> Rational(7,4)
  244.   #   r % Rational(1,2)    # -> Rational(1,4)
  245.   #   r % 1                # -> Rational(3,4)
  246.   #   r % Rational(1,7)    # -> Rational(1,28)
  247.   #   r % 0.26             # -> 0.19
  248.   #
  249.   def % (other)
  250.     value = (self / other).to_i
  251.     return self - other * value
  252.   end
  253.  
  254.   #
  255.   # Returns the quotient _and_ remainder.
  256.   #
  257.   # Examples:
  258.   #   r = Rational(7,4)        # -> Rational(7,4)
  259.   #   r.divmod Rational(1,2)   # -> [3, Rational(1,4)]
  260.   #
  261.   def divmod(other)
  262.     value = (self / other).to_i
  263.     return value, self - other * value
  264.   end
  265.  
  266.   #
  267.   # Returns the absolute value.
  268.   #
  269.   def abs
  270.     if @numerator > 0
  271.       Rational.new!(@numerator, @denominator)
  272.     else
  273.       Rational.new!(-@numerator, @denominator)
  274.     end
  275.   end
  276.  
  277.   #
  278.   # Returns +true+ iff this value is numerically equal to +other+.
  279.   #
  280.   # But beware:
  281.   #   Rational(1,2) == Rational(4,8)          # -> true
  282.   #   Rational(1,2) == Rational.new!(4,8)     # -> false
  283.   #
  284.   # Don't use Rational.new!
  285.   #
  286.   def == (other)
  287.     if other.kind_of?(Rational)
  288.       @numerator == other.numerator and @denominator == other.denominator
  289.     elsif other.kind_of?(Integer)
  290.       self == Rational.new!(other, 1)
  291.     elsif other.kind_of?(Float)
  292.       Float(self) == other
  293.     else
  294.       other == self
  295.     end
  296.   end
  297.  
  298.   #
  299.   # Standard comparison operator.
  300.   #
  301.   def <=> (other)
  302.     if other.kind_of?(Rational)
  303.       num = @numerator * other.denominator
  304.       num_a = other.numerator * @denominator
  305.       v = num - num_a
  306.       if v > 0
  307.     return 1
  308.       elsif v < 0
  309.     return  -1
  310.       else
  311.     return 0
  312.       end
  313.     elsif other.kind_of?(Integer)
  314.       return self <=> Rational.new!(other, 1)
  315.     elsif other.kind_of?(Float)
  316.       return Float(self) <=> other
  317.     elsif defined? other.coerce
  318.       x, y = other.coerce(self)
  319.       return x <=> y
  320.     else
  321.       return nil
  322.     end
  323.   end
  324.  
  325.   def coerce(other)
  326.     if other.kind_of?(Float)
  327.       return other, self.to_f
  328.     elsif other.kind_of?(Integer)
  329.       return Rational.new!(other, 1), self
  330.     else
  331.       super
  332.     end
  333.   end
  334.  
  335.   #
  336.   # Converts the rational to an Integer.  Not the _nearest_ integer, the
  337.   # truncated integer.  Study the following example carefully:
  338.   #   Rational(+7,4).to_i             # -> 1
  339.   #   Rational(-7,4).to_i             # -> -2
  340.   #   (-1.75).to_i                    # -> -1
  341.   #
  342.   # In other words:
  343.   #   Rational(-7,4) == -1.75                 # -> true
  344.   #   Rational(-7,4).to_i == (-1.75).to_i     # false
  345.   #
  346.   def to_i
  347.     Integer(@numerator.div(@denominator))
  348.   end
  349.  
  350.   #
  351.   # Converts the rational to a Float.
  352.   #
  353.   def to_f
  354.     @numerator.to_f/@denominator.to_f
  355.   end
  356.  
  357.   #
  358.   # Returns a string representation of the rational number.
  359.   #
  360.   # Example:
  361.   #   Rational(3,4).to_s          #  "3/4"
  362.   #   Rational(8).to_s            #  "8"
  363.   #
  364.   def to_s
  365.     if @denominator == 1
  366.       @numerator.to_s
  367.     else
  368.       @numerator.to_s+"/"+@denominator.to_s
  369.     end
  370.   end
  371.  
  372.   #
  373.   # Returns +self+.
  374.   #
  375.   def to_r
  376.     self
  377.   end
  378.  
  379.   #
  380.   # Returns a reconstructable string representation:
  381.   #
  382.   #   Rational(5,8).inspect     # -> "Rational(5, 8)"
  383.   #
  384.   def inspect
  385.     sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
  386.   end
  387.  
  388.   #
  389.   # Returns a hash code for the object.
  390.   #
  391.   def hash
  392.     @numerator.hash ^ @denominator.hash
  393.   end
  394.  
  395.   attr :numerator
  396.   attr :denominator
  397.  
  398.   private :initialize
  399. end
  400.  
  401. class Integer
  402.   #
  403.   # In an integer, the value _is_ the numerator of its rational equivalent.
  404.   # Therefore, this method returns +self+.
  405.   #
  406.   def numerator
  407.     self
  408.   end
  409.  
  410.   #
  411.   # In an integer, the denominator is 1.  Therefore, this method returns 1.
  412.   #
  413.   def denominator
  414.     1
  415.   end
  416.  
  417.   #
  418.   # Returns a Rational representation of this integer.
  419.   #
  420.   def to_r
  421.     Rational(self, 1)
  422.   end
  423.  
  424.   #
  425.   # Returns the <em>greatest common denominator</em> of the two numbers (+self+
  426.   # and +n+).
  427.   #
  428.   # Examples:
  429.   #   72.gcd 168           # -> 24
  430.   #   19.gcd 36            # -> 1
  431.   #
  432.   # The result is positive, no matter the sign of the arguments.
  433.   #
  434.   def gcd(other)
  435.     min = self.abs
  436.     max = other.abs
  437.     while min > 0
  438.       tmp = min
  439.       min = max % min
  440.       max = tmp
  441.     end
  442.     max
  443.   end
  444.  
  445.   #
  446.   # Returns the <em>lowest common multiple</em> (LCM) of the two arguments
  447.   # (+self+ and +other+).
  448.   #
  449.   # Examples:
  450.   #   6.lcm 7        # -> 42
  451.   #   6.lcm 9        # -> 18
  452.   #
  453.   def lcm(other)
  454.     if self.zero? or other.zero?
  455.       0
  456.     else
  457.       (self.div(self.gcd(other)) * other).abs
  458.     end
  459.   end
  460.  
  461.   #
  462.   # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments
  463.   # (+self+ and +other+).  This is more efficient than calculating them
  464.   # separately.
  465.   #
  466.   # Example:
  467.   #   6.gcdlcm 9     # -> [3, 18]
  468.   #
  469.   def gcdlcm(other)
  470.     gcd = self.gcd(other)
  471.     if self.zero? or other.zero?
  472.       [gcd, 0]
  473.     else
  474.       [gcd, (self.div(gcd) * other).abs]
  475.     end
  476.   end
  477. end
  478.  
  479. class Fixnum
  480.   undef quo
  481.   # If Rational is defined, returns a Rational number instead of a Fixnum.
  482.   def quo(other)
  483.     Rational.new!(self,1) / other
  484.   end
  485.   alias rdiv quo
  486.  
  487.   # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
  488.   def rpower (other)
  489.     if other >= 0
  490.       self.power!(other)
  491.     else
  492.       Rational.new!(self,1)**other
  493.     end
  494.   end
  495.  
  496.   unless defined? 1.power!
  497.     alias power! **
  498.     alias ** rpower
  499.   end
  500. end
  501.  
  502. class Bignum
  503.   unless defined? Complex
  504.     alias power! **
  505.   end
  506.  
  507.   undef quo
  508.   # If Rational is defined, returns a Rational number instead of a Bignum.
  509.   def quo(other)
  510.     Rational.new!(self,1) / other
  511.   end
  512.   alias rdiv quo
  513.  
  514.   # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
  515.   def rpower (other)
  516.     if other >= 0
  517.       self.power!(other)
  518.     else
  519.       Rational.new!(self, 1)**other
  520.     end
  521.   end
  522.  
  523.   unless defined? Complex
  524.     alias ** rpower
  525.   end
  526. end
  527.